import G6 from '@antv/g6';
import React, { useEffect, useRef, useState } from 'react';
import { Spin, Select, Layout } from 'antd';
import './index.less';
const Option = Select.Option;
const Content = Layout.Content;

const tooltip = new G6.Tooltip({
  offsetX: 10,
  offsetY: 10,
  fixToNode: [1, 0.5],
  // the types of items that allow the tooltip show up
  // 允许出现 tooltip 的 item 类型
  itemTypes: ['node', 'edge'],
  // custom the tooltip's content
  // 自定义 tooltip 内容
  getContent: (e) => {
    const outDiv = document.createElement('div');
    outDiv.style.width = 'fit-content';
    outDiv.style.height = 'fit-content';
    const model = e.item.getModel();
    if (e.item.getType() === 'node') {
      outDiv.innerHTML = `${model.label}`;
    } else {
      const source = e.item.getSource();
      const target = e.item.getTarget();
      outDiv.innerHTML = `来源：${source.getModel().label}<br/>去向：${target.getModel().label}`;
    }
    return outDiv;
  },
})

let graph;

function App() {

  const chartDomRef = useRef(null);
  const [loading, setLoading] = useState(false);
  const [size, setSize] = useState('50000');

  useEffect(() => {
    console.time('开始加载')
    setLoading(true)
    const container = chartDomRef.current;
    const width = container.scrollWidth;
    const height = container.scrollHeight || 500;
    graph = new G6.Graph({
      container,
      width,
      height,
      defaultNode: {
        size: 2,
        style: {
          fill: '#C6E5FF',
          stroke: '#5B8FF9',
          lineWidth: 0.3,
        },
        labelCfg: {
          style: {
            fontSize: 3,
          },
          position: 'right',
          offset: 1,
        },
      },
      defaultEdge: {
        size: 0.1,
        color: '#333',
        opacity: 0.2,
      },
      nodeStateStyles: {
        selected: {
          fill: 'steelblue',
          stroke: '#000',
          lineWidth: 1,
        },
      },
      modes: {
        default: [
          {
            type: 'zoom-canvas',
            enableOptimize: true,
            optimizeZoom: 0.9,
          },
          {
            type: 'drag-canvas',
            enableOptimize: true,
          },
          'drag-node',
          'brush-select',
        ],
      },
    });

    import(`../../api/data-${size}.json`).then(data => {
      graph.data(data)
      graph.render();
      const graphData = graph.save();
      const nodeLen = graphData.nodes.length;
      const edgeLen = graphData.edges.length;
      console.timeEnd('开始加载')
      setLoading(false)
    })

    return () => {
      console.log('卸载组件')
      if (graph) {
        graph.off();
        graph.destroy()
        graph = null;
      }
    }
  }, [])

  useEffect(() => {
    function windowResize() {
      const container = chartDomRef.current;
      if (!graph || graph.get('destroyed')) return;
      if (!container || !container.scrollWidth || !container.scrollHeight) return;
      graph.changeSize(container.scrollWidth, container.scrollHeight);
    }
    window.addEventListener('resize', windowResize)
    return () => {
      window.removeEventListener('resize', windowResize)
    }
  }, [])

  function clearAllStats() {
    if (!graph) return
    graph.setAutoPaint(false);
    graph.getNodes().forEach(function (node) {
      graph.clearItemStates(node);
    });
    graph.getEdges().forEach(function (edge) {
      graph.clearItemStates(edge);
    });
    graph.paint();
    graph.setAutoPaint(true);
  }


  function nodeMouseenter(e) {
    if (!graph) return
    const item = e.item;
    graph.setAutoPaint(false);
    graph.getNodes().forEach(function (node) {
      graph.clearItemStates(node);
      graph.setItemState(node, 'dark', true);
    });
    graph.setItemState(item, 'dark', false);
    graph.setItemState(item, 'highlight', true);
    graph.getEdges().forEach(function (edge) {
      if (edge.getSource() === item) {
        graph.setItemState(edge.getTarget(), 'dark', false);
        graph.setItemState(edge.getTarget(), 'highlight', true);
        graph.setItemState(edge, 'highlight', true);
        edge.toFront();
      } else if (edge.getTarget() === item) {
        graph.setItemState(edge.getSource(), 'dark', false);
        graph.setItemState(edge.getSource(), 'highlight', true);
        graph.setItemState(edge, 'highlight', true);
        edge.toFront();
      } else {
        graph.setItemState(edge, 'highlight', false);
        graph.setItemState(edge, 'dark', true);
      }
    });
    graph.paint();
    graph.setAutoPaint(true);
  }

  function nodeDragend(e) {
    e.item.get('model').fx = null;
    e.item.get('model').fy = null;
  }

  function afterlayout(e) {
    if (!graph) return
    graph.fitView()
  }

  function edgeClick(ev) {
    if (!graph) return
    const edge = ev.item;
    graph.setItemState(edge, 'selected', !edge.hasState('selected')); // 切换选中
  }

  function edgeMouseenter(ev) {
    if (!graph) return
    const edge = ev.item;
    graph.setItemState(edge, 'dark', false);
    graph.setItemState(edge, 'highlight', true);
  }

  function edgeMouseleave(ev) {
    if (!graph) return
    const edge = ev.item;
    graph.setItemState(edge, 'dark', false);
    graph.setItemState(edge, 'highlight', false);
  }


  function refreshDragedNodePosition(e) {
    const model = e.item.get('model');
    model.fx = e.x;
    model.fy = e.y;
  }

  function nodeDragstart(e) {
    if (!graph) return
    graph.layout();
    refreshDragedNodePosition(e);
  }

  function nodeDrag(e) {
    if (!graph) return
    const forceLayout = graph.get('layoutController').layoutMethods[0];
    forceLayout.execute();
    refreshDragedNodePosition(e);
  }

  function handleChangeDataSize(value) {
    setLoading(true);
    setSize(value);
    import(`../../api/data-${value}.json`).then(res => {
      const container = chartDomRef.current;
      const width = container.scrollWidth;
      const height = container.scrollHeight;
      let opiton;
      if (res.nodes.length > 10) {
        graph.off();
        opiton = {
          container,
          width,
          height,
          defaultNode: {
            size: 2,
            style: {
              fill: '#C6E5FF',
              stroke: '#5B8FF9',
              lineWidth: 0.3,
            },
            labelCfg: {
              style: {
                fontSize: 3,
              },
              position: 'right',
              offset: 1,
            },
          },
          defaultEdge: {
            size: 0.1,
            color: '#333',
            opacity: 0.2,
          },
          nodeStateStyles: {
            selected: {
              fill: 'steelblue',
              stroke: '#000',
              lineWidth: 1,
            },
          },
          modes: {
            default: [
              {
                type: 'zoom-canvas',
                enableOptimize: true,
                optimizeZoom: 0.9,
              },
              {
                type: 'drag-canvas',
                enableOptimize: true,
              },
              // 'drag-node',
              // 'brush-select',
            ],
          },
        }
      } else {
        // 支持可探索
        opiton = {
          container,
          width,
          height,
          linkCenter: false,
          animate: false,
          layout: {
            type: 'force',
            // edgeStrength: 0.7,
            preventOverlap: true,
          },
          // layout: {
          //   type: 'forceAtlas2',
          //   preventOverlap: true,
          //    kr: 10,
          //    center: [250, 250],
          // },
          plugins: [tooltip],
          modes: {
            default: ['zoom-canvas', 'drag-canvas', 'drag-node',],
            //'activate-relations'
          },
          defaultNode: {
            size: [10, 10],
            style: {
              cursor: 'move', //节点可移动
              lineWidth: 1,//描边宽度
              opacity: 1,//设置绘图的当前 alpha 或透明值
              fillOpacity: 1,//设置填充的 alpha 或透明值
            },
            labelCfg: {
              position: 'right',
              style: {
                fontSize: 8
              }
            }
          },
          defaultEdge: {
            type: 'quadratic', //曲线
            style: {
              endArrow: true, //默认箭头
              cursor: 'pointer',//曲线可点击
              lineWidth: 1,
              lineAppendWidth: 1,
              strokeOpacity: 1,
            },
            labelCfg: {
              refX: 0,
              refY: 0,
              position: 'middle',
              autoRotate: true,
              style: {
                fontSize: 8,
              }
            },
          },
          nodeStateStyles: {
            highlight: {
              opacity: 1,
              fillOpacity: 1,
            },
            dark: {
              opacity: 0.1,
              fillOpacity: 0.1,
            },
          },
          edgeStateStyles: {
            highlight: {
              strokeOpacity: 1,
            },
            dark: {
              strokeOpacity: 0.1
            },
          },
        }
        // graph.on('afterlayout', afterlayout);
        graph.on('node:dragstart', nodeDragstart); //开始拖拽
        graph.on('node:drag', nodeDrag); //拖拽中
        // graph.on('node:dragend', nodeDragend); //拖拽结束
        graph.on('node:mouseenter', nodeMouseenter);  //节点hover
        graph.on('node:mouseleave', clearAllStats); //节点blur
        graph.on('canvas:click', clearAllStats); //canvas click
        graph.on('edge:click', edgeClick); //edge click
        graph.on('edge:mouseenter', edgeMouseenter); //edge hover
        graph.on('edge:mouseleave', edgeMouseleave);//edge blur
      }
      graph.destroyLayout();
      graph.changeData({
        nodes: res.nodes,
        edges: res.edges
      });
      graph.updateLayout(opiton);
      graph.paint()
      graph.refresh();
      setLoading(false)
    })
  }


  return <Layout>
    <div >
      切换数据：<Select
        style={{
          width: 100
        }}
        onChange={handleChangeDataSize}
        value={size}
      >
        <Option value='10'>10</Option>
        <Option value='100'>100</Option>
        <Option value='500'>500</Option>
        <Option value='1000'>1000</Option>
        <Option value='2000'>2000</Option>
        <Option value='3000'>3000</Option>
        <Option value='4000'>4000</Option>
        <Option value='5000'>5000</Option>
        <Option value='6000'>6000</Option>
        <Option value='10000'>10000</Option>
        <Option value='50000'>50000</Option>
      </Select>
    </div>
    <Content>
      <Spin
        spinning={loading}
      >      </Spin>

      <div className="demo-container" ref={chartDomRef} />

    </Content>

  </Layout>


}

export default App;
